package ru.ifmo.croak.impl.ui.post.team3;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Scanner;
import java.util.UUID;

import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.WindowConstants;

import ru.ifmo.croak.api.Message;
import ru.ifmo.croak.api.PostService;
import ru.ifmo.croak.util.CroakFactory;

/**
 * A simple PostUI component. It can be run with either console or graphical
 * interface.<br/>
 * Usage: <tt>PostUI [-name name] [-author author] [-gui]</tt><br/>
 * where options are:
 * <ul>
 * <li><b>-name</b> &nbsp name of the PostUI instance, "ui.post" if not specified
 * <li><b>-author</b> &nbsp name of the author
 * <li><b>-gui</b> &nbsp if this argument is specified, GUI mode is enabled
 * </ul>
 * 
 * @author Mikhail Kever
 */
public class PostUI implements Runnable {
	public static void main(String[] args) {
		String name = ArgumentParser.getValue(args, ArgumentParser.POST_UI_NAME);
		if (name == null) {
			name = "ui.post";
		}
		String author = ArgumentParser.getValue(args, ArgumentParser.AUTHOR);
		boolean gui = ArgumentParser.haveArgument(args, ArgumentParser.GUI);
		new PostUI(name, gui, author).run();
	}

	private final String name;
	private String author;
	private PostService postService;
	private boolean guiMode;

	/**
	 * Creates a runnable {@link PostUI} which name is set to <tt>name</tt>.
	 * 
	 * @param name
	 *            name of the {@link PostUI} instance
	 */
	public PostUI(String name) {
		this(name, true);
	}

	/**
	 * Creates a runnable {@link PostUI} which name is set to <tt>name</tt>. If
	 * <tt>guiMode</tt> is <tt>true</tt>, this {@link PostUI} will run in GUI
	 * mode.
	 * 
	 * @param name
	 *            name of the {@link PostUI} instance
	 * @param guiMode
	 *            if <tt>guiMode</tt> is <tt>true</tt>, this {@link PostUI} will
	 *            run in GUI mode
	 */
	public PostUI(String name, boolean guiMode) {
		this.name = name;
		this.guiMode = guiMode;
	}

	/**
	 * Creates a runnable {@link PostUI} which name is set to <tt>name</tt> and
	 * author is set to <tt>author</tt>. If <tt>guiMode</tt> is <tt>true</tt>,
	 * this {@link PostUI} will run in GUI mode.
	 * 
	 * @param name
	 *            name of the {@link PostUI} instance
	 * @param guiMode
	 *            if <tt>guiMode</tt> is <tt>true</tt>, this {@link PostUI} will
	 *            run in GUI mode
	 * @param author
	 *            name of the author
	 */
	public PostUI(String name, boolean guiMode, String author) {
		this.name = name;
		this.guiMode = guiMode;
		this.author = author;
	}

	@Override
	public void run() {
		postService = getPostService();
		if (guiMode) {
			runGUI();
		} else {
			runConsole();
		}
	}

	/**
	 * Runs in GUI mode
	 */
	private void runGUI() {
		createGUI();
	}

	/**
	 * Runs in console mode
	 */
	private void runConsole() {
		Scanner in = new Scanner(System.in);
		if (this.author == null) {
			System.out.println("Usage hint: postUI [-name name] [-author author] [-gui]");
			System.out.println("Enter your name:");
			author = in.nextLine();
		}
		while (in.hasNext()) {
			String text = in.nextLine();
			postMessage(text);
		}
	}

	/**
	 * Posts message which text is set to <tt>text</tt>.
	 * 
	 * @param text
	 *            message text
	 */
	private void postMessage(String text) {
		Message message = new Message();
		message.setAuthor(author);
		message.setId(UUID.randomUUID());
		message.setTime(System.currentTimeMillis());
		message.setText(text);
		postService.postMessage(message);
	}

	/**
	 * Gets post service implementation from {@link CroakFactory}
	 * 
	 * @return an instance of {@link PostService}
	 */
	private PostService getPostService() {
		String postProviderName = CroakFactory.getInstance().getProperty(name + ".provider");
		return CroakFactory.getInstance().getImplementation(PostService.class, postProviderName);
	}

	/**
	 * Creates GUI
	 */
	private void createGUI() {
		final JFrame frame;
		final JLabel authorLabel, messageLabel;
		final JTextField authorField;
		final JTextField messageField;
		final JButton postIt;

		frame = new JFrame("Post");
		frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

		authorLabel = new JLabel("Author:");
		authorField = new JTextField(this.author);
		authorField.setMaximumSize(new Dimension(200, 20));

		messageLabel = new JLabel("Message:");
		messageField = new JTextField();
		messageField.setMaximumSize(new Dimension(1000, 20));

		postIt = new JButton("Croak!");

		GroupLayout layout = new GroupLayout(frame.getContentPane());
		frame.getContentPane().setLayout(layout);
		layout.setAutoCreateGaps(true);
		layout.setAutoCreateContainerGaps(true);

		layout.setHorizontalGroup(layout
				.createSequentialGroup()
				.addGroup(
						layout.createParallelGroup().addComponent(authorLabel)
								.addComponent(messageLabel))
				.addGroup(
						layout.createParallelGroup().addComponent(authorField)
								.addComponent(messageField).addComponent(postIt)));
		layout.setVerticalGroup(layout
				.createSequentialGroup()
				.addGroup(
						layout.createParallelGroup().addComponent(authorLabel)
								.addComponent(authorField))
				.addGroup(
						layout.createParallelGroup().addComponent(messageLabel)
								.addComponent(messageField)).addComponent(postIt));

		postIt.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				author = authorField.getText();
				postMessage(messageField.getText());
			}
		});

		frame.setPreferredSize(new Dimension(250, 150));
		frame.pack();
		frame.setVisible(true);
	}

	/**
	 * A simple command line argument parser for {@link PostUI}.
	 * 
	 * @author Mikhail Kever
	 * 
	 */
	private static class ArgumentParser {
		private static final String POST_UI_NAME = "-name";
		private static final String AUTHOR = "-author";
		private static final String GUI = "-gui";

		/**
		 * Checks if <tt>argumentName</tt> is listed in <tt>args</tt>
		 * 
		 * @param args
		 *            array of arguments
		 * @param argumentName
		 *            argument name
		 * @return <tt>true</tt> if <tt>argumentName</tt> is listed in
		 *         <tt>args</tt>
		 */
		private static boolean haveArgument(String[] args, String argumentName) {
			for (String arg : args) {
				if (arg != null && arg.equals(argumentName)) {
					return true;
				}
			}
			return false;
		}

		/**
		 * Returns the value assigned to <tt>argumentName</tt> according to
		 * <tt>args</tt>.
		 * 
		 * @param args
		 *            array of arguments
		 * @param argumentName
		 *            argument name
		 * @return the value assigned to <tt>argumentName</tt>
		 */
		private static String getValue(String[] args, String argumentName) {
			for (int i = 0; i + 1 < args.length; i++) {
				if (args[i] != null && args[i].equals(argumentName)) {
					return args[i + 1];
				}
			}
			return null;
		}
	}

}
